package com.lcy.struct.bTreePlus.disk.recovery.redo;

import com.lcy.struct.bTreePlus.entity.RedoInfo;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @author lucongyang
 * @date Created in  14:28
 * @description
 */
public class NoForceDurationEngine {
    private static final Object SYNC_LOCK = new Object();
    private static ReentrantReadWriteLock LOCK = new ReentrantReadWriteLock();
    private static final Lock WRITE_LOCK = LOCK.writeLock();
    private static final Lock READ_LOCK = LOCK.readLock();
    private List<RedoInfo> redoList;
    private int corePoolSize = Runtime.getRuntime().availableProcessors();
    private int maximumPoolSize = corePoolSize * 2;
    private long keepAliveTime = 60L;
    private ThreadPoolExecutor threadPoolExecutor;

    public void join(RedoInfo redoInfo) {
        this.redoList.add(redoInfo);
    }

    public void noForceDuration() {
        if (threadPoolExecutor.getActiveCount() < 1) {
            CompletableFuture.runAsync(this::backendTask, threadPoolExecutor);
        }
    }

    private void backendTask() {
        synchronized (SYNC_LOCK) {
            List<RedoInfo> list;
            WRITE_LOCK.lock();
            try {
                list = this.redoList;
                this.redoList = new ArrayList<>();
            } finally {
                WRITE_LOCK.unlock();
            }
            RedoCenter.getInstance().doRedo(list);
            READ_LOCK.lock();
            try {
                if (!this.redoList.isEmpty()) {
                    READ_LOCK.unlock();
                    backendTask();
                } else {
                    System.out.println("持久化节点结束！");
                }
            } finally {
                READ_LOCK.unlock();
            }
        }
    }

    public static NoForceDurationEngine getInstance() {
        return Singleton.INSTANCE;
    }

    private static class Singleton {
        private static final NoForceDurationEngine INSTANCE = new NoForceDurationEngine();
    }

    private NoForceDurationEngine() {
        redoList = new ArrayList<>();
        this.threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
                keepAliveTime, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(100),
                Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
    }
}
